﻿using Acme.BookStore.Purchase.Customergoods;
using Acme.BookStore.PurchaseDto.CustomergoodsDto;
using Acme.BookStore.PurchaseDto.OtherwarehousingDto;
using Microsoft.DotNet.PlatformAbstractions;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Caching.Distributed;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Caching;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Identity;
using System.Linq.Dynamic.Core;
using Microsoft.EntityFrameworkCore;
using Acme.BookStore.Purchase.NotificationOrder;
using Acme.BookStore.Purchase.ReceiptOrder;

namespace Acme.BookStore.Purchase.Otherwarehousing
{
    public class OtherwarehousingServices: CrudAppService
        <OtherwarehousingModel, OtherwarehousingDto, Guid, PagedResultRequestDto, CreateUpdateOtherwarehousingDto>, IOtherwarehousingServices
    {
        private readonly IRepository<IdentityUser, Guid> _userRepository;
        private readonly IDistributedCache<PagedResultDto<OtherwarehousingDto>, string> _otherwarehousingDtoCache;
        private readonly ILogger<OtherwarehousingServices> _logger;

        public OtherwarehousingServices(
            IRepository<OtherwarehousingModel, Guid> repository,
            IRepository<IdentityUser, Guid> userRepository, 
            IDistributedCache<PagedResultDto<OtherwarehousingDto>, string>otherwarehousingDtoCache,
            ILogger<OtherwarehousingServices> logger)
            :base(repository)
        {
            _userRepository = userRepository;
            _otherwarehousingDtoCache = otherwarehousingDtoCache;
            _logger = logger;
        }

        public async Task<ListResultDto<IOtherwarehousingServices.OrderTypeModelDto>> GetOrderTypeModelAsync()
        {
            var list = Enum.GetValues(typeof(OrderTypeModel))
               .Cast<OrderTypeModel>()
               .Select(x => new IOtherwarehousingServices.OrderTypeModelDto
               {
                   Id = (int)x,
                   Name = x.ToString()
               }).ToList();

            return new ListResultDto<IOtherwarehousingServices.OrderTypeModelDto>(list);
        }

        public async Task<ListResultDto<IOtherwarehousingServices.PlatformDto>> GetPlatformDtoModelAsync()
        {
            var list = Enum.GetValues(typeof(PlatformEnum))
              .Cast<PlatformEnum>()
              .Select(x => new IOtherwarehousingServices.PlatformDto
              {
                  Id = (int)x,
                  Name = x.ToString()
              }).ToList();

            return new ListResultDto<IOtherwarehousingServices.PlatformDto>(list);
        }

        public async Task<ListResultDto<IOtherwarehousingServices.ReservedWarehouseAreaModelDto>> GetReservedWarehouseAreaModelAsync()
        {
            var list = Enum.GetValues(typeof(ReservedWarehouseAreaModel))
                .Cast<ReservedWarehouseAreaModel>()
                .Select(x => new IOtherwarehousingServices.ReservedWarehouseAreaModelDto
                {
                    Id = (int)x,
                    Name = x.ToString()
                }).ToList();

            return new ListResultDto<IOtherwarehousingServices.ReservedWarehouseAreaModelDto>(list);
        }

        public async Task<ListResultDto<IOtherwarehousingServices.WarehouseModelDto>> GetWarehouseModelAsync()
        {
            var list = Enum.GetValues(typeof(WarehouseModel))
                .Cast<WarehouseModel>()
                .Select(x => new IOtherwarehousingServices.WarehouseModelDto
                {
                    Id = (int)x,
                    Name = x.ToString()
                }).ToList();

            return new ListResultDto<IOtherwarehousingServices.WarehouseModelDto>(list);
        }

        /// <summary>
        /// 根据条件查询其他入库单
        /// </summary>
        public async Task<PagedResultDto<OtherwarehousingDto>> GetListByConditionsAsync(OtherwarehousingQueryDto input)
        {
            try
            {
                // 构建缓存键
                var cacheKey = $"OtherwarehousingQuery:{input.PurchaseOrderNo}:{input.ExpectedArrivalDateFrom}:{input.ExpectedArrivalDateTo}:{input.CustomerOrderNo}:{input.CarNo}:{input.DriverName}:{input.DriverPhone}:{input.Status}:{input.Platform}";

                // 尝试从缓存获取
                var cachedResult = await _otherwarehousingDtoCache.GetAsync(cacheKey);
                if (cachedResult != null)
                {
                    _logger.LogInformation($"Cache hit for key: {cacheKey}");
                    return cachedResult;
                }
                _logger.LogInformation($"Cache miss for key: {cacheKey}");

                // 获取查询对象
                var query = await Repository.GetQueryableAsync();

                // 应用查询条件
                query = query.WhereIf(
                    !string.IsNullOrWhiteSpace(input.PurchaseOrderNo),
                    x => x.OrderNo.Contains(input.PurchaseOrderNo)
                ).WhereIf(
                    !string.IsNullOrWhiteSpace(input.OwnerCode),
                    x => x.OwnerCode.Contains(input.OwnerCode)
                ).WhereIf(
                    input.OrderType.HasValue,
                    x => x.OrderType == input.OrderType
                )
                .WhereIf(
                    input.ExpectedArrivalDateFrom.HasValue,
                    x => x.EstimatedArrivalTime >= input.ExpectedArrivalDateFrom.Value
                )
                .WhereIf(
                    input.ExpectedArrivalDateTo.HasValue,
                    x => x.EstimatedArrivalTime <= input.ExpectedArrivalDateTo.Value
                )
                .WhereIf(
                    !string.IsNullOrWhiteSpace(input.CustomerOrderNo),
                    x => x.CustomerOrderNo.Contains(input.CustomerOrderNo)
                )
                .WhereIf(
                    !string.IsNullOrWhiteSpace(input.CarNo),
                    x => x.CarNo.Contains(input.CarNo)
                )
                .WhereIf(
                    !string.IsNullOrWhiteSpace(input.DriverName),
                    x => x.DriverName.Contains(input.DriverName)
                )
                .WhereIf(
                    !string.IsNullOrWhiteSpace(input.DriverPhone),
                    x => x.DriverPhone.Contains(input.DriverPhone)
                )
                .WhereIf(
                    !string.IsNullOrWhiteSpace(input.Status),
                    x => x.Status == input.Status
                )
                .WhereIf(
                    input.Platform.HasValue,
                    x => x.Platform == input.Platform
                );

                // 获取总数
                var totalCount = await AsyncExecuter.CountAsync(query);

                // 排序和分页
                var items = await AsyncExecuter.ToListAsync(
                    query.OrderBy(input.Sorting ?? nameof(OtherwarehousingModel.Id))
                        .Skip(input.SkipCount)
                        .Take(input.MaxResultCount)
                );

                // 转换为DTO
                var dtos = ObjectMapper.Map<List<OtherwarehousingModel>, List<OtherwarehousingDto>>(items);
                var result = new PagedResultDto<OtherwarehousingDto>(totalCount, dtos);

                // 保存到缓存
                await _otherwarehousingDtoCache.SetAsync(
                    cacheKey,
                    result,
                    new DistributedCacheEntryOptions
                    {
                        AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(10)
                    }
                );

                return result;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error occurred while searching other warehousing records");
                throw;
            }
        }

        // 四表联查DTO
        public class MergedWarehouseReceiptDto
        {
            public Guid? CustomergoodsId { get; set; }
            // CustomergoodsModel字段
            public string? CustomergoodsPurchaseOrderNo { get; set; }
            public string? CustomergoodsSupplierCode { get; set; }
            public string? CustomergoodsCarNo { get; set; }
            public string? CustomergoodsDriverName { get; set; }
            public string? CustomergoodsDriverPhone { get; set; }
            public string? CustomergoodsStatus { get; set; }
            public string? CustomergoodsShipper { get; set; }
            public DateTime? CustomergoodsEstimatedArrivalTime { get; set; }
            public string? CustomergoodsCustomerOrderNo { get; set; }
            public string? CustomergoodsTransportNo { get; set; }
            public string? CustomergoodsTransportCompany { get; set; }
            public string? CustomergoodsSupplier { get; set; }
            public ReservedWarehouseAreaModel? CustomergoodsReservedWarehouseArea { get; set; }
            public WarehouseModel? CustomergoodsWarehouse { get; set; }
            public OrderTypeModel? CustomergoodsOrderType { get; set; }
            public string? CustomergoodsRemarks { get; set; }
            public string? CustomergoodsAttachmentPath { get; set; }

            // OtherwarehousingModel字段
            public Guid? OtherwarehousingId { get; set; }
            public string? OtherwarehousingOrderNo { get; set; }
            public string? OtherwarehousingOwnerCode { get; set; }
            public PlatformEnum? OtherwarehousingPlatform { get; set; }
            public string? OtherwarehousingCarNo { get; set; }
            public string? OtherwarehousingDriverName { get; set; }
            public string? OtherwarehousingDriverPhone { get; set; }
            public string? OtherwarehousingStatus { get; set; }
            public string? OtherwarehousingShipper { get; set; }
            public DateTime? OtherwarehousingEstimatedArrivalTime { get; set; }
            public string? OtherwarehousingCustomerOrderNo { get; set; }
            public string? OtherwarehousingTransportNo { get; set; }
            public string? OtherwarehousingTransportCompany { get; set; }
            public string? OtherwarehousingSupplier { get; set; }
            public ReservedWarehouseAreaModel? OtherwarehousingReservedWarehouseArea { get; set; }
            public WarehouseModel? OtherwarehousingWarehouse { get; set; }
            public OrderTypeModel? OtherwarehousingOrderType { get; set; }
            public string? OtherwarehousingRemarks { get; set; }
            public string? OtherwarehousingAttachmentPath { get; set; }

            // ReceiptOrders字段
            public Guid? ReceiptOrderId { get; set; }
            public string? ReceiptOrderNoticeNo { get; set; }
            public string? ReceiptOrderCustomerNode { get; set; }
            public string? ReceiptOrderShipper { get; set; }
            public string? ReceiptOrderTray { get; set; }
            public string? ReceiptOrderStorageLocation { get; set; }
            public bool? ReceiptOrderIsShelved { get; set; }
            public string? ReceiptOrderProduct { get; set; }
            public string? ReceiptOrderProductCode { get; set; }
            public string? ReceiptOrderUnit { get; set; }
            public int? ReceiptOrderArrivalQty { get; set; }
            public int? ReceiptOrderQty { get; set; }
            public decimal? ReceiptOrderVolume { get; set; }
            public decimal? ReceiptOrderWeight { get; set; }
            public DateTime? ReceiptOrderProductionDate { get; set; }
            public string? ReceiptOrderBatch { get; set; }
            public decimal? ReceiptOrderReceiptTemperature { get; set; }
            public string? ReceiptOrderRemark { get; set; }
            public decimal? ReceiptOrderInWeight { get; set; }
            public decimal? ReceiptOrderOutWeight { get; set; }

            // NotificationOrders字段
            public Guid? NotificationOrderId { get; set; }
            public string? NotificationOrderNo { get; set; }
            public string? NotificationOrderCustomerCode { get; set; }
            public string? NotificationOrderCustomerName { get; set; }
            public string? NotificationOrderStatus { get; set; }
            public string? NotificationOrderProductCode { get; set; }
            public string? NotificationOrderProductName { get; set; }
            public decimal? NotificationOrderQty { get; set; }
            public decimal? NotificationOrderReceivedQty { get; set; }
            public string? NotificationOrderUnit { get; set; }
            public decimal? NotificationOrderVolumeCm3 { get; set; }
            public decimal? NotificationOrderWeightKg { get; set; }
            public string? NotificationOrderCustomerOrderNo { get; set; }
            public decimal? NotificationOrderBaseUnitQty { get; set; }
            public string? NotificationOrderBaseUnit { get; set; }
            public DateTime? NotificationOrderProductionDate { get; set; }
        }

        // 四表联查接口
        public async Task<List<MergedWarehouseReceiptDto>> GetMergedWarehouseReceiptAsync()
        {
            var customergoodsRepo = LazyServiceProvider.LazyGetRequiredService<IRepository<CustomergoodsModel, Guid>>();
            var otherwarehousingRepo = LazyServiceProvider.LazyGetRequiredService<IRepository<OtherwarehousingModel, Guid>>();
            var receiptOrderRepo = LazyServiceProvider.LazyGetRequiredService<IRepository<ReceiptOrders, Guid>>();
            var notificationOrderRepo = LazyServiceProvider.LazyGetRequiredService<IRepository<NotificationOrders, Guid>>();

            var customergoodsQuery = await customergoodsRepo.GetQueryableAsync();
            var otherwarehousingQuery = await otherwarehousingRepo.GetQueryableAsync();
            var receiptOrderQuery = await receiptOrderRepo.GetQueryableAsync();
            var notificationOrderQuery = await notificationOrderRepo.GetQueryableAsync();

            var query = from c in customergoodsQuery
                        join o in otherwarehousingQuery on c.CustomerOrderNo equals o.CustomerOrderNo into coGroup
                        from o in coGroup.DefaultIfEmpty()
                        join r in receiptOrderQuery on c.CustomerOrderNo equals r.CustomerNode into crGroup
                        from r in crGroup.DefaultIfEmpty()
                        join n in notificationOrderQuery on c.CustomerOrderNo equals n.CustomerOrderNo into cnGroup
                        from n in cnGroup.DefaultIfEmpty()
                        select new MergedWarehouseReceiptDto
                        {
                            // CustomergoodsModel字段
                            CustomergoodsId = c.Id,
                            CustomergoodsPurchaseOrderNo = c.PurchaseOrderNo,
                            CustomergoodsSupplierCode = c.SupplierCode,
                            CustomergoodsCarNo = c.CarNo,
                            CustomergoodsDriverName = c.DriverName,
                            CustomergoodsDriverPhone = c.DriverPhone,
                            CustomergoodsStatus = c.Status,
                            CustomergoodsShipper = c.Shipper,
                            CustomergoodsEstimatedArrivalTime = c.EstimatedArrivalTime,
                            CustomergoodsCustomerOrderNo = c.CustomerOrderNo,
                            CustomergoodsTransportNo = c.TransportNo,
                            CustomergoodsTransportCompany = c.TransportCompany,
                            CustomergoodsSupplier = c.Supplier,
                            CustomergoodsReservedWarehouseArea = c.ReservedWarehouseArea,
                            CustomergoodsWarehouse = c.Warehouse,
                            CustomergoodsOrderType = c.OrderType,
                            CustomergoodsRemarks = c.Remarks,
                            CustomergoodsAttachmentPath = c.AttachmentPath,

                            // OtherwarehousingModel字段
                            OtherwarehousingId = o != null ? o.Id : null,
                            OtherwarehousingOrderNo = o != null ? o.OrderNo : null,
                            OtherwarehousingOwnerCode = o != null ? o.OwnerCode : null,
                            OtherwarehousingPlatform = o != null ? o.Platform : null,
                            OtherwarehousingCarNo = o != null ? o.CarNo : null,
                            OtherwarehousingDriverName = o != null ? o.DriverName : null,
                            OtherwarehousingDriverPhone = o != null ? o.DriverPhone : null,
                            OtherwarehousingStatus = o != null ? o.Status : null,
                            OtherwarehousingShipper = o != null ? o.Shipper : null,
                            OtherwarehousingEstimatedArrivalTime = o != null ? o.EstimatedArrivalTime : null,
                            OtherwarehousingCustomerOrderNo = o != null ? o.CustomerOrderNo : null,
                            OtherwarehousingTransportNo = o != null ? o.TransportNo : null,
                            OtherwarehousingTransportCompany = o != null ? o.TransportCompany : null,
                            OtherwarehousingSupplier = o != null ? o.Supplier : null,
                            OtherwarehousingReservedWarehouseArea = o != null ? o.ReservedWarehouseArea : null,
                            OtherwarehousingWarehouse = o != null ? o.Warehouse : null,
                            OtherwarehousingOrderType = o != null ? o.OrderType : null,
                            OtherwarehousingRemarks = o != null ? o.Remarks : null,
                            OtherwarehousingAttachmentPath = o != null ? o.AttachmentPath : null,

                            // ReceiptOrders字段
                            ReceiptOrderId = r != null ? r.Id : null,
                            ReceiptOrderNoticeNo = r != null ? r.NoticeNo : null,
                            ReceiptOrderCustomerNode = r != null ? r.CustomerNode : null,
                            ReceiptOrderShipper = r != null ? r.Shipper : null,
                            ReceiptOrderTray = r != null ? r.Tray : null,
                            ReceiptOrderStorageLocation = r != null ? r.StorageLocation : null,
                            ReceiptOrderIsShelved = r != null ? r.IsShelved : null,
                            ReceiptOrderProduct = r != null ? r.Product : null,
                            ReceiptOrderProductCode = r != null ? r.ProductCode : null,
                            ReceiptOrderUnit = r != null ? r.Unit : null,
                            ReceiptOrderArrivalQty = r != null ? r.ArrivalQty : null,
                            ReceiptOrderQty = r != null ? r.Qty : null,
                            ReceiptOrderVolume = r != null ? r.Volume : null,
                            ReceiptOrderWeight = r != null ? r.Weight : null,
                            ReceiptOrderProductionDate = r != null ? r.ProductionDate : null,
                            ReceiptOrderBatch = r != null ? r.Batch : null,
                            ReceiptOrderReceiptTemperature = r != null ? r.ReceiptTemperature : null,
                            ReceiptOrderRemark = r != null ? r.Remark : null,
                            ReceiptOrderInWeight = r != null ? r.InWeight : null,
                            ReceiptOrderOutWeight = r != null ? r.OutWeight : null,

                            // NotificationOrders字段
                            NotificationOrderId = n != null ? n.Id : null,
                            NotificationOrderNo = n != null ? n.NotificationOrderNo : null,
                            NotificationOrderCustomerCode = n != null ? n.CustomerCode : null,
                            NotificationOrderCustomerName = n != null ? n.CustomerName : null,
                            NotificationOrderStatus = n != null ? n.NotificationStatus : null,
                            NotificationOrderProductCode = n != null ? n.ProductCode : null,
                            NotificationOrderProductName = n != null ? n.ProductName : null,
                            NotificationOrderQty = n != null ? n.NotificationQty : null,
                            NotificationOrderReceivedQty = n != null ? n.ReceivedQty : null,
                            NotificationOrderUnit = n != null ? n.Unit : null,
                            NotificationOrderVolumeCm3 = n != null ? n.VolumeCm3 : null,
                            NotificationOrderWeightKg = n != null ? n.WeightKg : null,
                            NotificationOrderCustomerOrderNo = n != null ? n.CustomerOrderNo : null,
                            NotificationOrderBaseUnitQty = n != null ? n.BaseUnitQty : null,
                            NotificationOrderBaseUnit = n != null ? n.BaseUnit : null,
                            NotificationOrderProductionDate = n != null ? n.ProductionDate : null
                        };
            return await query.Take(100).ToListAsync();
        }
    }
}
